home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 6 / CU Amiga Magazine's Super CD-ROM 06 (1996)(EMAP Images)(GB)(Track 1 of 4)[!][issue 1997-01].iso / cucd / graphics / whirlgif201 / src.original / whirlgif.c < prev    next >
C/C++ Source or Header  |  1996-11-01  |  18KB  |  825 lines

  1.   
  2. /*
  3.  * whirlgif.c
  4.  *
  5.  * Copyright (C) 1995,1996 by Kevin Kadow (kadokev@msg.net)
  6.  * 
  7.  * Based on txtmerge.c
  8.  * Copyright (C) 1990,1991,1992,1993 by Mark Podlipec. 
  9.  * All rights reserved.
  10.  *
  11.  * This software may be freely copied, modified and redistributed
  12.  * without fee provided that this copyright notice is preserved 
  13.  * intact on all copies and modified copies.
  14.  * 
  15.  * There is no warranty or other guarantee of fitness of this software.
  16.  * It is provided solely "as is". The author(s) disclaim(s) all
  17.  * responsibility and liability with respect to this software's usage
  18.  * or its effect upon hardware or computer systems.
  19.  *
  20.  */
  21.  /*
  22.   * Description:
  23.   *
  24.   * This program reads in a sequence of single-image GIF format files and
  25.   * outputs a single multi-image GIF file, suitable for use as an animation.
  26.   *
  27.   * TODO:
  28.   *
  29.   * More options for dealing with the colormap
  30.   *
  31.   * Eventually, I'd like to have this program compare the current image
  32.   * with the previous image and check to see if only a small section of
  33.   * the screen changed from the previous image. Worth a shot.
  34.   */
  35.  
  36.  /*
  37.   * Rev 2.01    31Aug96 Kevin Kadow
  38.   *    disposal
  39.   * Rev 2.00    05Feb96 Kevin Kadow
  40.   *    transparency, gif comments,
  41.   * Rev 1.10    29Jan96 Kevin Kadow
  42.   *    first release of whirlgif
  43.   *
  44.   * txtmerge:
  45.   * Rev 1.00    23Jul91    Mark Podlipec
  46.   *    creation
  47.   * Rev 1.01    08Jan92    Mark Podlipec
  48.   *     use all colormaps, not just 1st.
  49.   *
  50.   * 
  51.   */
  52. #define DA_REV 2.01
  53.  
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #ifdef _USE_STRINGS_H
  57. #include <strings.h>
  58. #else
  59. #include <string.h>
  60. #endif
  61.  
  62. #include "whirlgif.h"
  63.  
  64. #define MAXVAL  4100            /* maxval of lzw coding size */
  65. #define MAXVALP 4200
  66.  
  67. /*
  68.  * Set some defaults, these can be changed on the command line
  69.  */
  70. unsigned int loop=DEFAULT_LOOP,loopcount=0,
  71.     use_colormap=DEFAULT_USE_COLORMAP,
  72.     debug_flag=0,
  73.     verbose=0;
  74.  
  75. int imagex = 0;
  76. int imagey = 0;
  77. int imagec = 0;
  78.  
  79. /* global settings for offset, transparency */
  80. Global global;
  81.  
  82. GIF_Color gif_cmap[256];
  83.  
  84. ULONG GIF_Get_Code();
  85. void GIF_Decompress();
  86. void GIF_Get_Next_Entry();
  87. void GIF_Add_To_Table();
  88. void GIF_Send_Data();
  89. void GIF_Clear_Table();
  90. void GIF_Screen_Header();
  91. void GIF_Image_Header();
  92. void GIF_Read_File();
  93. void GIF_Comment();
  94. void GIF_Loop();
  95. void GIF_GCL();
  96. void Calc_Trans();
  97. void set_offset();
  98.  
  99. GIF_Screen_Hdr gifscrn;
  100. GIF_Image_Hdr gifimage;
  101. GIF_Table table[MAXVALP];
  102.  
  103. ULONG root_code_size,code_size,CLEAR,EOI,INCSIZE;
  104. ULONG nextab;
  105. ULONG gif_mask[16] = {1,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,0,0};
  106. ULONG gif_ptwo[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,0,0};
  107.  
  108.  
  109. UBYTE gif_buff[MAXVALP];
  110. ULONG gif_block_size;
  111. int num_bits,bits;
  112.  
  113. int pic_i;
  114. char gif_file_name[BIGSTRING];
  115. int screen_was_last;
  116.  
  117.  
  118. void TheEnd()
  119. {
  120.  exit(0);
  121. }
  122.  
  123. void TheEnd1(p)
  124. char *p;
  125. {
  126.  fprintf(stderr,"%s",p);
  127.  TheEnd();
  128. }
  129.  
  130. Usage()
  131. {
  132.   fprintf(stderr,"\nUsage: whirlgif [-o outfile] [-loop [count]] [-time #delay]\n");
  133.   fprintf(stderr,"\t[-disp_none | -disp_back | -disp_prev | -disp_not]\n");
  134.   fprintf(stderr,"\t[ -i listfile] file1 [ -time #delay] file2 ...\n");
  135.   exit(0);
  136. }
  137.  
  138. main(argc,argv)
  139. int argc;
  140. char *argv[];
  141. {
  142.  FILE * infile, *fout;
  143.  char temp[BIGSTRING];
  144.  int ret,i;
  145.  int count=0;
  146.  
  147.  fprintf(stderr,"whirlgif Rev %2.2f (C) 1996 by Kevin Kadow\n",DA_REV);
  148.  fprintf(stderr,"                  (C) 1991,1992 by Mark Podlipec\n");
  149.  
  150.  if (argc < 2) Usage();
  151.  
  152.  /* set global values */
  153.  screen_was_last = FALSE;
  154.  global.trans.type=TRANS_NONE;
  155.  global.trans.valid=FALSE;
  156.  global.time=DEFAULT_TIME;
  157.  global.left=0;
  158.  global.top=0;
  159.  global.disposal=DEFAULT_DISPOSAL;
  160.  
  161.  
  162.  fout=stdout;
  163.  i = 1;
  164.  while( i < argc)
  165.  {
  166.   char *p;
  167.   p = argv[i];
  168.   /*fprintf(stderr,"Option: %s\n",p);*/
  169.   if ( (p[0] == '-') || (p[0] == '+') )
  170.   { 
  171.    ++p; /* strip off the - */
  172.    switch(p[0])
  173.    {
  174.     case 'v':    /* Give lots of information */
  175.             verbose++;
  176.             i++;
  177.         fprintf(stderr,"Verbose output\n");
  178.         break;
  179.  
  180.     case 'd':    /* either Debug mode or disposal setting */
  181.         i++;
  182.         if(!strncmp("disp",p,4)) {
  183.             i++;
  184.             p=argv[1];
  185.             p++;
  186.               if(verbose) fprintf(stderr,"Disposal method set\n");
  187.             if(!strcmp("none",p)) 
  188.                global.disposal = DISP_NONE;
  189.             else if(!strcmp("not",p)) 
  190.                global.disposal = DISP_NOT;
  191.             else if(!strcmp("back",p)) 
  192.                global.disposal = DISP_BACK;
  193.             else if(!strcmp("prev",p)) 
  194.                global.disposal = DISP_PREV;
  195.             else global.disposal = DISP_NONE;
  196.         }
  197.         else {
  198.             debug_flag++;
  199.             fprintf(stderr,"DEBUG: Debug Level %d\n",debug_flag);
  200.         }
  201.         break;
  202.  
  203.     case 'l':    /* Enable looping */
  204.         loop=TRUE;
  205.         i++;
  206.         if(*argv[i] !='-') {
  207.           /* a loop count was given */
  208.           loopcount=atoi(argv[i++]);
  209.           if(verbose) fprintf(stderr,"Loop %d times\n",loopcount);
  210.           }
  211.         else {
  212.           /* default to infinite loop */
  213.           loopcount=0;
  214.           if(verbose) fputs("Looping enabled\n",stderr);
  215.           }
  216.         break;
  217.  
  218.     case 'u':    /* Use colormap? true or false */
  219.         i++;
  220.         if(atoi(argv[i]) || !strcmp("true",argv[i])) use_colormap=1;
  221.         else use_colormap=0;
  222.         i++;
  223.         break;
  224.  
  225.     case 't':    /* either time or transparent */
  226.         i++;
  227.         if(!strcmp("time",p)) {
  228.             /* Delay time in 1/100's of a second */
  229.             global.time=atoi(argv[i++]);
  230.             }
  231.         else if(!strncmp("trans",p,4)) Calc_Trans(argv[i++]);
  232.         break;
  233.  
  234.     case 'o':    /* Output file - send output to a given filename */
  235.         i++;
  236.         if(!strncmp("off",p,3)) set_offset(argv[i]);
  237.         else
  238.         /* It must be 'output, so do that */
  239.         if(NULL==(fout=fopen(argv[i],"w")))
  240.             {
  241.             fprintf(stderr,"Cannot open %s for output\n",argv[i]);
  242.             exit(1);
  243.             }
  244.         i++;
  245.         break;
  246.     case 'i':    /* input file - file with a list of images */
  247.         i++;
  248.         if(NULL != (infile=fopen(argv[i],"r"))) {
  249.             while(fgets(gif_file_name,BIGSTRING,infile)) {
  250.                 strtok(gif_file_name,"\n");
  251.                   if(!count) GIF_Read_File(fout,gif_file_name,1);
  252.                   else       GIF_Read_File(fout,gif_file_name,0);
  253.                   count++;
  254.                 }
  255.             fclose(infile);
  256.             }
  257.         else fprintf(stderr,"Cannot read list file %s\n",argv[i]);
  258.         i++;
  259.         break;
  260.     default: 
  261.         Usage();
  262.         exit(0);
  263.         break;
  264.    }
  265.    continue;
  266.   }
  267.   /* Not an option, must be the name of an input file */
  268.   if(!count) GIF_Read_File(fout,argv[i],1);
  269.   else       GIF_Read_File(fout,argv[i],0);
  270.   count++;
  271.   i++;
  272.  }
  273.  /* We're done with all the options, finish up */
  274.  if(count >0)
  275.   {
  276.   fputc(';',fout); /* image separator */
  277.   sprintf(temp,"whirlgif %2.2f (C) kadokev@msg.net. %d images",DA_REV,count);
  278.   GIF_Comment(fout,temp);
  279.   }
  280.  
  281.  fclose(fout);
  282.  fprintf(stderr,"Processed %d files.\n",count);
  283.  exit(0);
  284. }
  285.  
  286.  
  287. /*
  288.  * Read a GIF file, outputting to fname as we go.
  289.  * It would be faster to read and write the individual blocks,
  290.  * but eventually we'd like to optimize based on changes from
  291.  * previous images(ie only a small section of the image changed.
  292.  */
  293. void
  294. GIF_Read_File(fout,fname,first_image)
  295. FILE * fout;
  296. char *fname;
  297. int first_image;
  298. {
  299.  FILE *fp;
  300.  int ret,i,exit_flag;
  301.  
  302.  if ( (fp=fopen(fname,"r"))==0)
  303.  { 
  304.   fprintf(stderr,"Can't open %s for reading.\n",fname); 
  305.   TheEnd();
  306.  }
  307.  
  308.  GIF_Screen_Header(fp,fout,first_image);
  309.  
  310.  /*** read until  ,  separator */
  311.  do
  312.  {
  313.   i=fgetc(fp);
  314.   if ( (i<0) && feof(fp))
  315.   {
  316.    fclose(fp);
  317.    TheEnd1("GIF_Read_Header: Unexpected End of File\n");
  318.   }
  319.  } while(i != ',');
  320.  
  321.  if(first_image)
  322.   {
  323.    /* stuff we only do once */
  324.    if(loop) GIF_Loop(fout,loopcount);
  325.    }
  326.  if(global.time||(global.trans.type!=TRANS_NONE && global.trans.valid))
  327.     GIF_GCL(fout,global.time);
  328.  
  329.  fputc(',',fout); /* image separator */
  330.  
  331.  GIF_Image_Header(fp,fout,first_image);
  332.  
  333.  /*FOO*/
  334.  
  335.  /*** Setup ACTION for IMAGE */
  336.  
  337.  GIF_Decompress(fp,fout,0);
  338.  fputc(0,fout);  /* block count of zero */
  339.  
  340.  fclose(fp);
  341. }
  342.  
  343. void GIF_Decompress(fp,fout)
  344. FILE *fp,*fout;
  345. {
  346.  register ULONG code,old;
  347.  
  348.  pic_i = 0;
  349.  bits=0;
  350.  num_bits=0;
  351.  gif_block_size=0;
  352.     /* starting code size of LZW */
  353.  root_code_size=(fgetc(fp) & 0xff); fputc(root_code_size,fout);
  354.  GIF_Clear_Table();                /* clear decoding symbol table */
  355.  
  356.  code=GIF_Get_Code(fp,fout);
  357.  
  358.  if (code==CLEAR) 
  359.  {
  360.   GIF_Clear_Table(); 
  361.   code=GIF_Get_Code(fp,fout);
  362.  }
  363.  /* write code(or what it currently stands for) to file */
  364.  GIF_Send_Data(code);   
  365.  old=code;
  366.  code=GIF_Get_Code(fp,fout);
  367.  do
  368.  {
  369.   if (table[code].valid==1)    /* if known code */
  370.   {
  371.        /* send it's associated string to file */
  372.     GIF_Send_Data(code);
  373.     GIF_Get_Next_Entry(fp);       /* get next table entry (nextab) */
  374.     GIF_Add_To_Table(old,code,nextab);  /* add old+code to table */
  375.     old=code;
  376.   }
  377.   else      /* code doesn't exist */
  378.   {
  379.     GIF_Add_To_Table(old,old,code);   /* add old+old to table */
  380.     GIF_Send_Data(code);
  381.     old=code;
  382.   }
  383.   code=GIF_Get_Code(fp,fout);
  384.   if (code==CLEAR)
  385.   { 
  386.    GIF_Clear_Table();
  387.    code=GIF_Get_Code(fp,fout);
  388.    GIF_Send_Data(code);
  389.    old=code;
  390.    code=GIF_Get_Code(fp,fout);
  391.   }
  392.  } while(code!=EOI);
  393. }
  394.  
  395. void GIF_Get_Next_Entry(fp)
  396. FILE *fp;
  397. {
  398.    /* table walk to empty spot */
  399.  while(  (table[nextab].valid==1)
  400.        &&(nextab<MAXVAL)
  401.       ) nextab++;
  402.  /* 
  403.   * Ran out of space?!  Something's gone sour...
  404.   */
  405.  if (nextab>=MAXVAL)    
  406.  { 
  407.   fprintf(stderr,"Error: GetNext nextab=%d\n",nextab);
  408.   fclose(fp);
  409.   TheEnd();
  410.  }
  411.  if (nextab==INCSIZE)   /* go to next table size (and LZW code size ) */
  412.  {
  413.    /* fprintf(stderr,"GetNext INCSIZE was %d ",nextab); */
  414.    code_size++; INCSIZE=(INCSIZE*2)+1;
  415.    if (code_size>=12) code_size=12;
  416. /*   fprintf(stderr,"<%d>",INCSIZE); */
  417.  }
  418.  
  419. }
  420. /*  body is associated string
  421.     next is code to add to that string to form associated string for
  422.     index
  423. */     
  424.  
  425. void GIF_Add_To_Table(body,next,index)
  426. register ULONG body,next,index;
  427. {
  428.  if (index>MAXVAL)
  429.  { 
  430.   fprintf(stderr,"Error index=%d\n",index);
  431.  }
  432.  else
  433.  {
  434.   table[index].valid=1;
  435.   table[index].data=table[next].first;
  436.   table[index].first=table[body].first;
  437.   table[index].last=body;
  438.  }
  439. }
  440.  
  441. void GIF_Send_Data(index)
  442. register int index;
  443. {
  444.  register int i,j;
  445.  i=0;
  446.  do         /* table walk to retrieve string associated with index */
  447.  { 
  448.   gif_buff[i]=table[index].data; 
  449.   i++;
  450.   index=table[index].last;
  451.   if (i>MAXVAL)
  452.   { 
  453.    fprintf(stderr,"Error: Sending i=%d index=%d\n",i,index);
  454.    TheEnd();
  455.   }
  456.  } while(index>=0);
  457.  
  458.  /* now invert that string since we retreived it backwards */
  459.  i--;
  460.  for(j=i;j>=0;j--)
  461.  {
  462.   /*pic[pic_i] = gif_buff[j] | gif_pix_offset;*/
  463.   pic_i++;
  464.  }
  465. }
  466.  
  467.  
  468. /* 
  469.  * initialize string table 
  470.  */
  471. void GIF_Init_Table()       
  472. {
  473.  register int maxi,i;
  474.  
  475. if (debug_flag) fprintf(stderr,"Initing Table...");
  476.  maxi=gif_ptwo[root_code_size];
  477.  for(i=0; i<maxi; i++)
  478.  {
  479.   table[i].data=i;   
  480.   table[i].first=i;
  481.   table[i].valid=1;  
  482.   table[i].last = -1;
  483.  }
  484.  CLEAR=maxi; 
  485.  EOI=maxi+1; 
  486.  nextab=maxi+2;
  487.  INCSIZE = (2*maxi)-1;
  488.  code_size=root_code_size+1;
  489. }
  490.  
  491.  
  492. /* 
  493.  * clear table 
  494.  */
  495. void GIF_Clear_Table()   
  496. {
  497.  register int i;
  498. if (debug_flag) fprintf(stderr,"Clearing Table...\n");
  499.  for(i=0;i<MAXVAL;i++) table[i].valid=0;
  500.  GIF_Init_Table();
  501. }
  502.  
  503. /*CODE*/
  504. ULONG GIF_Get_Code(fp,fout) /* get code depending of current LZW code size */
  505. FILE *fp,*fout;
  506. {
  507.  ULONG code;
  508.  register int tmp;
  509.  
  510.  while(num_bits < code_size)
  511.  {
  512.   /**** if at end of a block, start new block */
  513.   if (gif_block_size==0) 
  514.   {
  515.    tmp = fgetc(fp);
  516.    if (tmp >= 0 )
  517.    {
  518.     fputc(tmp,fout);
  519.     gif_block_size=(ULONG)(tmp);
  520.    }
  521.    else TheEnd1("EOF in data stream\n");
  522.   }
  523.  
  524.   tmp = fgetc(fp);   gif_block_size--;
  525.   if (tmp >= 0)
  526.   {
  527.    fputc(tmp,fout);
  528.    bits |= ( ((ULONG)(tmp) & 0xff) << num_bits );
  529.    num_bits+=8;
  530.   }
  531.   else TheEnd1("EOF in data stream\n");
  532.  }
  533.   
  534.  code = bits & gif_mask[code_size];
  535.  bits >>= code_size;
  536.  num_bits -= code_size; 
  537.  
  538.  
  539.  if (code>MAXVAL)
  540.  { 
  541.   fprintf(stderr,"\nError! in stream=%x \n",code); 
  542.   fprintf(stderr,"CLEAR=%x INCSIZE=%x EOI=%x code_size=%x \n",
  543.                                            CLEAR,INCSIZE,EOI,code_size); 
  544.   code=EOI;
  545.  }
  546.  
  547.  if (code==INCSIZE)
  548.  {
  549.   if (code_size<12)
  550.   {
  551.    code_size++; INCSIZE=(INCSIZE*2)+1;
  552.   }
  553.   else if (debug_flag) fprintf(stderr,"<13?>"); 
  554.  }
  555.  
  556.  return(code);
  557. }
  558.  
  559.  
  560. /* 
  561.  * read GIF header 
  562.  */
  563. void GIF_Screen_Header(fp,fout,first_time)
  564. FILE *fp,*fout;
  565. int first_time;
  566. {
  567.  int temp,i;
  568.  
  569.  for(i=0;i<6;i++)
  570.  {
  571.   temp = fgetc(fp);
  572.   if(i==4 && temp == '7') temp='9';
  573.   if (first_time==TRUE) fputc(temp,fout);
  574.  }
  575.  
  576.  gifscrn.width  = GIF_Get_Short(fp,fout,first_time);
  577.  gifscrn.height = GIF_Get_Short(fp,fout,first_time);
  578.  temp=fgetc(fp);                 if (first_time==TRUE) fputc(temp,fout);
  579.  gifscrn.m       =  temp & 0x80;
  580.  gifscrn.cres    = (temp & 0x70) >> 4;
  581.  gifscrn.pixbits =  temp & 0x07;
  582.  
  583.  gifscrn.bc  = fgetc(fp);
  584.  if (first_time==TRUE) 
  585.     {
  586.     /* we really should set the background color to the transparent color */
  587.     fputc(gifscrn.bc,fout);
  588.     }
  589.  
  590.  temp=fgetc(fp);                 if (first_time==TRUE) fputc(temp,fout);
  591.  imagec=gif_ptwo[(1+gifscrn.pixbits)];
  592.  
  593.  if (verbose)
  594.   fprintf(stderr,"Screen: %dx%dx%d m=%d cres=%d bkgnd=%d pix=%d\n",
  595.     gifscrn.width,gifscrn.height,imagec,gifscrn.m,gifscrn.cres,
  596.     gifscrn.bc,gifscrn.pixbits);
  597.  
  598.  if(global.trans.type==TRANS_RGB) global.trans.valid=0;
  599.  if (gifscrn.m)
  600.  {
  601.   for(i=0;i<imagec;i++)
  602.   {
  603.    gif_cmap[i].cmap.red   = temp = fgetc(fp); 
  604.            if (first_time==TRUE) fputc(temp,fout);
  605.    gif_cmap[i].cmap.green = temp = fgetc(fp); 
  606.            if (first_time==TRUE) fputc(temp,fout);
  607.    gif_cmap[i].cmap.blue  = temp = fgetc(fp); 
  608.            if (first_time==TRUE) fputc(temp,fout);
  609.  
  610.    if(global.trans.type==TRANS_RGB && !global.trans.valid)
  611.     if(global.trans.red==gif_cmap[i].cmap.red &&
  612.     global.trans.green==gif_cmap[i].cmap.green &&
  613.     global.trans.blue==gif_cmap[i].cmap.blue) {
  614.       if(debug_flag>1) fprintf(stderr," Transparent match at %d\n",i);
  615.         global.trans.map=i;
  616.     global.trans.valid=TRUE;
  617.     }
  618.   }
  619.  }
  620.  screen_was_last = TRUE;
  621. }
  622.  
  623. void GIF_Image_Header(fp,fout,first_time)
  624. FILE *fp,*fout;
  625. int first_time;
  626. {
  627.  int temp,tnum,i,r,g,b;
  628.  
  629.  gifimage.left   = GIF_Get_Short(fp,fout,1);
  630.  if(global.left) gifimage.left+=global.left;
  631.  
  632.  gifimage.top    = GIF_Get_Short(fp,fout,1);
  633.  if(global.top) gifimage.top+=global.top;
  634.  
  635.  gifimage.width  = GIF_Get_Short(fp,fout,1);
  636.  gifimage.height = GIF_Get_Short(fp,fout,1);
  637.  temp=fgetc(fp); 
  638.  
  639.  
  640.     
  641.  gifimage.i        = temp & 0x40;
  642.  gifimage.pixbits  = temp & 0x07;
  643.  gifimage.m        = temp & 0x80;
  644.  
  645.  /* this sets the local colormap bit to true */
  646.  if (screen_was_last && (first_time==FALSE)) temp |= 0x80;
  647.  
  648.  temp &= 0xf8;
  649.  temp |= gifscrn.pixbits;
  650.  fputc(temp,fout);
  651.  
  652.  imagex=gifimage.width;
  653.  imagey=gifimage.height;
  654.  tnum=gif_ptwo[(1+gifimage.pixbits)];
  655.  if (verbose)
  656.   fprintf(stderr,"Image: %dx%dx%d (%d,%d) m=%d i=%d pix=%d \n",
  657.     imagex,imagey,tnum,gifimage.left,gifimage.top,
  658.     gifimage.m,gifimage.i,gifimage.pixbits);
  659.  
  660.  /* if there is an image cmap, then use it */
  661.  
  662.  if (gifimage.m)
  663.  {
  664.   if(debug_flag) fprintf(stderr,"DEBUG:Transferring colormap of %d colors\n",
  665.             imagec);
  666.   for(i=0;i<tnum;i++)
  667.   {
  668.    gif_cmap[i].cmap.red   = r = fgetc(fp);
  669.    gif_cmap[i].cmap.green = g = fgetc(fp);
  670.    gif_cmap[i].cmap.blue  = b = fgetc(fp);
  671.    fputc(r,fout);
  672.    fputc(g,fout);
  673.    fputc(b,fout);
  674.   }
  675.  }  /* else if screen was last not 1st time */
  676.  else if (screen_was_last && (first_time==FALSE))
  677.  {
  678.   if(debug_flag>1) fprintf(stderr,"DEBUG:Writing colormap of %d colors\n",
  679.             imagec);
  680.   for(i=0;i<imagec;i++)
  681.   {
  682.    fputc(gif_cmap[i].cmap.red  ,fout);
  683.    fputc(gif_cmap[i].cmap.green,fout);
  684.    fputc(gif_cmap[i].cmap.blue ,fout);
  685.   }
  686.  }
  687.  screen_was_last = FALSE; 
  688. }
  689.  
  690.  
  691. /*
  692.  *
  693.  */
  694. int GIF_Get_Short(fp,fout,first_time)
  695. FILE *fp,*fout;
  696. int first_time;
  697. {
  698.  register int temp,tmp1;
  699.  temp=fgetc(fp);     if (first_time==TRUE) fputc(temp,fout);
  700.  tmp1=fgetc(fp);     if (first_time==TRUE) fputc(tmp1,fout);
  701.  return(temp|( (tmp1) << 8 ));
  702. }
  703.  
  704. void GIF_Comment(fout,string)
  705. FILE *fout;
  706. char *string;
  707. {
  708. if(!string || !strlen(string))
  709.         {
  710.         /* Bogus string */
  711.         if(debug_flag) fprintf(stderr,"GIF_Comment: invalid argument");
  712.         return;
  713.         }
  714. fputc(0x21,fout);
  715. fputc(0xFE,fout);
  716. fputs(string,fout);
  717. fputc(0,fout);
  718. }
  719.  
  720. /*
  721.  * Write a Netscape loop marker.
  722.  */
  723. void GIF_Loop(fout,repeats)
  724. FILE *fout;
  725. unsigned int repeats;
  726. {
  727. UBYTE low=0,high=0;
  728. if(repeats) {
  729.     /* non-zero repeat count- Netscape hasn't implemented this yet */
  730.     high=repeats / 256;
  731.     low=repeats % 256;
  732.     }
  733.  
  734. fputc(0x21,fout);
  735. fputc(0xFF,fout);
  736. fputc(0x0B,fout);
  737. fputs("NETSCAPE2.0",fout);
  738. fputc(0x03,fout);
  739. fputc(0x01,fout);
  740.  
  741. fputc(low,fout); /* the delay count - 0 for infinite */
  742. fputc(high,fout); /* second byte of delay count */
  743. fputc(0x00,fout); /* terminator */
  744.  
  745. if(verbose) fprintf(stderr,"Wrote loop extension\n");
  746. }
  747.  
  748. /*
  749.  * GIF_GCL - add a Control Label to set an inter-frame delay value.
  750.  */
  751. void GIF_GCL(fout,delay)
  752. FILE * fout;
  753. unsigned int delay;
  754. {
  755. UBYTE low=0,high=0,flag;
  756. if(delay) {
  757.     /* non-zero delay, figure out low/high bytes */
  758.     high=delay / 256;
  759.     low=delay % 256;
  760.     }
  761.  
  762. fputc(0x21,fout);
  763. fputc(0xF9,fout);
  764. fputc(0x04,fout);
  765.  
  766. flag = global.disposal <<2;
  767. if(delay) flag |=0x80;
  768. if(global.trans.valid) flag |=0x01;
  769. fputc(flag,fout);
  770.  
  771. fputc(low,fout); /* the delay speed - 0 is instantaneous */
  772. fputc(high,fout); /* second byte of delay count */
  773.  
  774. fputc(global.trans.map,fout);
  775. fputc(0,fout);
  776. if(debug_flag>1) {
  777.   fprintf(stderr,"GCL: delay %d",delay);
  778.   if(global.trans.valid) fprintf(stderr," Transparent: %d",global.trans.map);
  779.   fputc('\n',stderr);
  780.   }
  781. }
  782.  
  783.  
  784. void Calc_Trans(string)
  785. char * string;
  786. {
  787. if(string[0] != '#') {
  788.   global.trans.type=TRANS_MAP;
  789.   global.trans.map=atoi(string);
  790.   global.trans.valid=1;
  791.   }
  792. else
  793.   {
  794.   /* it's an RGB value */
  795.   int r,g,b;
  796.   string++;
  797.   if(3==sscanf(string,"%2x%2x%2x",&r,&g,&b)) {
  798.     global.trans.red=r;
  799.     global.trans.green=g;
  800.     global.trans.blue=b;
  801.     global.trans.type=TRANS_RGB;
  802.     if(debug_flag) fprintf(stderr,"Transparent RGB=(%x,%x,%x)\n",r,g,b);
  803.     }
  804.   }
  805. if(debug_flag) fprintf(stderr,"DEBUG:Calc_trans is %d\n",global.trans.type);
  806. }
  807.  
  808. void set_offset(string)
  809. char * string;
  810. {
  811. char *off_x,*off_y;
  812. off_x=(char *) strtok(string,",");
  813. off_y=(char *)strtok((char *)NULL,",");
  814. if(off_x && off_y) {
  815.     /* set the offset */
  816.     global.left=atoi(off_x);
  817.     global.top=atoi(off_y);
  818.     if(debug_flag>1) fprintf(stderr,"Offset changed to %d,%d\n",
  819.         global.left,global.top);
  820.     return;
  821.     }
  822. if(debug_flag>1) fprintf(stderr,"Couldn't parse offset values.\n");
  823. exit(1);
  824. }
  825.